﻿using System;
using System.Collections;
using System.Collections.Generic;
//using System.Linq;
using System.Text;
using System.Threading;
using KZ400B.Link;

namespace KZ400B
{
    public class CommLockedException : Exception
    {
        public override string Message
        {
            get
            {
                return "通讯信道被占用";
            }
        }
    }

    public class nUnCompatibleFrameException : Exception
    {
        public override string Message
        {
            get
            {
                return "响应帧不匹配";
            }
        }
    }

    public class MsgItem
    {
        private long m_Id;

        public long Id
        {
            get { return m_Id; }
            //set { m_Id = value; }
        }
        private string m_Msg;

        public string Msg
        {
            get { return m_Msg; }
            //set { m_Msg = value; }
        }

        public MsgItem(long id, string msg)
        {
            m_Id = id;
            m_Msg = msg;
        }
    }
    public partial class AxleManager
    {
        private static SerialPortLink spLink = null;
        private static object s_spLocker = new object();
        private static object s_spflgLocker = new object();
        
        //public static event AxlePositionChange OnAxlePostionChange;
        public static event AxleActionResponse OnAxleActionResponse;

      

        #region 系统运行变量
        private static object s_commLocker = new object();//通讯运行锁   //自动接收线程锁
        private static volatile bool s_rFlag = false;//通讯是否运行


        private static bool isCommRunning()
        {
            lock (s_commLocker)
            {
                return s_rFlag;
            }
        }

        private static void setCommRunning(bool flag)
        {
            lock (s_commLocker)
            {
                s_rFlag = flag;
            }
        }
        #endregion

        public static bool IsOpen
        {
            get
            {
                bool rst = spLink != null && spLink.IsOpen;
                if (!rst)
                {
                    Data.AxleStateBarMsg.Instance.AxleState = "请打开连接";
                }
                return rst;
            }
        }

        

        public static bool Open(SPort sPort)
        {
            setCommRunning(true);

            spLink = new SerialPortLink();
            bool rst = spLink.Open(sPort);
            if (rst)
            {
                try
                {
                    rst = Contact();
                }
                catch (Exception ex)
                {
                    if (OnAxleActionResponse != null)
                    {
                        OnAxleActionResponse(
                            Axle.AllAxleName
                            , new Axle(Axle.AllAxleName)
                            , AxleActions.Failed
                            , rst
                            , string.Format("联系指令失败:{0}", ex.Message)
                            );
                    }
                }
                if (rst)
                {
                    s_tRecv = new Thread(new ThreadStart(doRecv));
                    s_tRecv.Start();

                    if (s_tMsgProc == null)
                    {
                        s_tMsgProc = new Thread(new ThreadStart(procMsg));
                        s_tMsgProc.Start();
                    }

                    OnContactRespond(rst);
                }
            }
            if (OnAxleActionResponse != null)
            {
                OnAxleActionResponse(
                    Axle.AllAxleName
                    , new Axle(Axle.AllAxleName)
                    , AxleActions.ContactRespond
                    , rst
                    , string.Format("联系指令:{0}", rst ? "成功" : "失败")
                    );
            }
            if (!rst)
            {
                try
                {
                    if (spLink != null)
                    {
                        spLink.Close();
                    }
                }
                catch (Exception ex)
                {
                    Utility.FileOperate.WriteToLog(ex.Message);
                }
            }
            return rst;
        }

        public static void Close()
        {
            try
            {
                if (AxleCacheManager.AxleList != null)
                {
                    foreach (string ax in AxleCacheManager.AxleList.Keys)
                    {
                        if (ax != null)
                        {
                            if (AxleCacheManager.AxleList[ax].AxleStatus != AxleStatus.Stoped)
                            {
                                AxleManager.Stop(ax);
                                AxleCacheManager.AxleList[ax].AxleStatus = AxleStatus.Stoped;
                            }
                        }
                    }
                    Thread.Sleep(1000);
                }
                setCommRunning(false);
                spLink.Close();
                spLink = null;
                s_tRecv = null;
                s_tMsgProc = null;
            }
            catch (Exception ex)
            {
                if (OnAxleActionResponse != null)
                {
                    OnAxleActionResponse(
                        Axle.AllAxleName
                        , new Axle(Axle.AllAxleName)
                        , AxleActions.Failed
                        , false
                        , string.Format("关闭连接失败:{0}", ex.Message)
                        );
                }
            }
            GC.WaitForPendingFinalizers();
        }
        
        static void setState(string state)
        {
            //if (OnStateChanged != null && !string.IsNullOrEmpty(state))
            //{
            //    OnStateChanged(null,state);
            //}
            Data.AxleStateBarMsg.Instance.AxleState = state;
        }

        /// <summary>
        /// 收到"=OK"联系成功
        /// </summary>
        /// <returns></returns>
        public static bool Contact()
        {
            if (!IsOpen)
            {
                return false;
            }

            string data = Protocol.Packet(Protocol.GetContactString());

            bool rst = sendData(data);
            if (rst)
            {
                try
                {

                    lock (s_spLocker)
                    {
                        if (spLink.CanRead)
                        {
                            string msg = spLink.ReadString(2);
                            if (string.IsNullOrEmpty(msg))
                            {
                                return false;
                            }
                            ProtocolV2.UnpacketResult ur = ProtocolV2.Unpack(msg);
                            rst = ur.Result && ur.Action == AxleActions.ContactRespond;
                        }
                    }// link lock
                }
                finally
                {
                    //setIsLocked(false);
                }
            }
            return rst;
        }//contact

        static void OnContactRespond(bool result)
        {
            if (result)
            {
                ///dsp断电后保存不了位置信息,所以连接后暂时不查询位置
                ///信息保存在dsp中,恢复位置查询
                foreach (string aName in AxleCacheManager.AxleList.Keys)
                {
                    //AxleManager.QueryPosition(aName);
                    //Thread.Sleep(300);
                    AxleManager.QueryPositionIM(aName);
                }
                

                foreach (string aName in AxleCacheManager.AxleList.Keys)
                {
                    int aLevel = AxleCacheManager.AxleList[aName].RunAcceleration;
                    if (aLevel != Axle.AccelerationLevel.Constant)
                    {
                        Axle.AccelerationLevel acc = new Axle.AccelerationLevel(aLevel);
                        //AxleManager.AccelerationSetting(aName, acc);
                        //Thread.Sleep(200);
                        AxleManager.AccelerationSettingIM(aName, acc);


                        //if (AxleManager.AccelerationSetting(ur.AxleName, acc))
                        //{
                        //    setState(
                        //    string.Format("({0} 轴|[{1}])加速度设置成功"
                        //        , ur.AxleName, acc.ToString()
                        //        )
                        //    );
                        //}
                        //else
                        //{
                        //    setState(
                        //    string.Format("({0} 轴|[{1}])加速度设置失败"
                        //        , ur.AxleName, acc.ToString()
                        //        )
                        //    );
                        //}
                    }
                }

                foreach (string aName in AxleCacheManager.AxleList.Keys)
                {
                    //AxleManager.QueryPosition(aName);
                    //Thread.Sleep(300);
                    if (AxleCacheManager.AxleList.ContainsKey(aName))
                    {
                        AxleManager.StepperAngleFractionIM(aName, AxleCacheManager.AxleList[aName].AxleDetailSetting);
                    }
                }
                
                
            }
            foreach (string aName in AxleCacheManager.AxleList.Keys)
            {
                if (AxleCacheManager.AxleList.ContainsKey(aName))
                {
                    AxleCacheManager.AxleList[aName].OtherAxleStatus = AxleActions.ContactRespond;
                    AxleCacheManager.AxleList[aName].AxleStatus = AxleStatus.Stoped;
                }
            }
        }




        /// <summary>
        /// 加速度参数设置
        /// </summary>
        /// <param name="axleName"></param>
        /// <param name="aLevel"></param>
        /// <returns></returns>
        public static bool AccelerationSetting(
        string axleName
        , Axle.AccelerationLevel aLevel
        )
        {
            if (!IsOpen)
            {
                return false;
            }
            

            string data = Protocol.Packet(
                Protocol.GetAccelerationSettingString(axleName, aLevel)
                );
            bool rst =  sendData(data);
            if (rst)
            {
                AxleCacheManager.AxleList[axleName].TargetParametersSetting.Acceleration = aLevel.IntValue;
            }
            return rst;
        }


        /// <summary>
        /// 加速度参数设置
        /// </summary>
        /// <param name="axleName"></param>
        /// <param name="aLevel"></param>
        /// <returns></returns>
        public static bool AccelerationSettingIM(
        string axleName
        , Axle.AccelerationLevel aLevel
        )
        {
            if (!IsOpen)
            {
                return false;
            }


            string data = Protocol.Packet(
                Protocol.GetAccelerationSettingString(axleName, aLevel)
                );
            bool rst = sendData(data);
            if (rst)
            {
                AxleCacheManager.AxleList[axleName].TargetParametersSetting.Acceleration = aLevel.IntValue;
                lock (s_spLocker)
                {
                    if (spLink.CanRead)
                    {
                        string msg = spLink.ReadString(2);
                        if (string.IsNullOrEmpty(msg))
                        {
                            return false;
                        }
                        ProtocolV2.UnpacketResult ur = ProtocolV2.Unpack(msg);
                        rst = ur.Result && ur.Action == AxleActions.AccelerationSettingRespond;
                        if (!rst)
                        {
                            return rst;
                        }
                        OnAccelerationSettingRespond(ur);

                        
                        return true;
                    }
                }// link lock
            }
            return rst;
        }

        static void OnAccelerationSettingRespond(ProtocolV2.UnpacketResult ur)
        {
            int aLevel = 0;
            if (ur.Result && ur.Action == AxleActions.AccelerationSettingRespond)
            {
                if (AxleCacheManager.AxleList.ContainsKey(ur.AxleName))
                {
                    aLevel = AxleCacheManager.AxleList[ur.AxleName].TargetParametersSetting.Acceleration;
                    AxleCacheManager.AxleList[ur.AxleName].RunAcceleration = aLevel;
                    AxleCacheManager.Update(ur.AxleName);
                }
                Axle.AccelerationLevel acc = new Axle.AccelerationLevel(aLevel);
                setState(
                string.Format("加速度({0}|[{1}])设置成功"
                    , ur.AxleName, acc.ToString()
                    )
                );
                    

            }
            if (AxleCacheManager.AxleList.ContainsKey(ur.AxleName))
            {
                AxleCacheManager.AxleList[ur.AxleName].OtherAxleStatus = AxleActions.AccelerationSettingRespond;
                AxleCacheManager.AxleList[ur.AxleName].AxleStatus = AxleStatus.Stoped;
            }
        }

        /// <summary>
        /// 查询指令是否成功
        /// </summary>
        /// <returns></returns>
        public static bool QuerySuccess()
        {
            if (!IsOpen)
            {
                return false;
            }
            
            string data = Protocol.Packet(
                Protocol.GetQuerySuccessString()
                );
            return sendData(data);
        }


        private static bool sendData(string data)
        {
            bool rst = false;
            try
            {

                lock (s_spLocker)
                {
                    if (spLink.CanWrite)
                    {
                        rst = spLink.Write(data) > 0;

                    }
                }// link lock
            }
            finally
            {
                //setIsLocked(false);
            }
            return rst;
        }


    }//class AxleManager
}//namespace
